# (C) Copyright 2016-2022 Intel Corporation.
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
"""Build CaRT components"""
from datetime import date

import SCons.Action

SRC = ['crt_bulk.c', 'crt_context.c', 'crt_corpc.c',
       'crt_ctl.c', 'crt_debug.c', 'crt_group.c', 'crt_hg.c', 'crt_hg_proc.c',
       'crt_init.c', 'crt_iv.c', 'crt_register.c',
       'crt_rpc.c', 'crt_self_test_client.c', 'crt_self_test_service.c',
       'crt_swim.c', 'crt_tree.c', 'crt_tree_flat.c', 'crt_tree_kary.c',
       'crt_tree_knomial.c']


def parse_pp(env, pp_targets):
    """Use command builder to process each preprocessed file"""
    results = []
    scope = r"'/struct [^ ]*_\(in\|out\) {/,/};/p'"
    sed_e = r"-e 's/\s\s*/ /g' -e 's/};struct /};\nstruct /g'"
    for tgt in pp_targets:
        fname = f"{tgt.abspath}_grep"
        cmd = f"sed -n {scope} $SOURCE | tr -d '\\n' | sed {sed_e} > $TARGET"
        results.extend(env.Command(fname, tgt, cmd))
    return results


def copy_header(**kw):
    """Copy the target file to source directory"""
    Execute(Copy(Dir("src/cart").srcnode().abspath, kw['target'][0].abspath))


def consolidate_pp(env, parsed_targets):
    """Consolidate parsed headers"""
    sed_d = r"-e 's/\([{;]\) /\1\t/g' -e 's/\([{;]\)/\1\n/g'"
    grepv = r"'struct sockaddr_in {'"
    preamble = env.Substfile('macro_prefix.h_in', SUBST_DICT={'@YEAR@': date.today().year})
    parsed_sources = [x.abspath for x in parsed_targets]
    cmd = (f"cat {preamble[0].abspath} > $TARGET; cat {' '.join(parsed_sources)}"
           + f" | grep -v {grepv} | sort -u | sed {sed_d} >> $TARGET")
    header = env.Command('_structures_from_macros.h', preamble + parsed_targets, cmd)
    env.AddPostAction(header, SCons.Action.Action(copy_header, None))
    return header


def scons():
    """Scons function"""

    # Generate the common libraries used by everyone
    SConscript('swim/SConscript')
    SConscript('utils/SConscript')

    Default('swim')

    Import('env', 'swim_targets', 'CART_VERSION')

    env.d_add_build_rpath()

    env.Alias('install', '$PREFIX')

    # There is probably a better way to do this but let's get it linking first
    env.AppendUnique(LIBPATH=[Dir('.')])

    env.require('mercury', headers_only=True)

    # Needed in order to include src/object/obj_rpc.h
    env.require('isal', headers_only=True)

    denv = env.Clone(LIBS=[])

    denv.AppendUnique(LIBS=['gurt'])
    denv.require('mercury')

    cart_targets = denv.SharedObject(SRC)

    compiler = env.get('COMPILER').lower()
    if compiler != 'covc':
        pp_env = denv.Clone()
        pp_files = []
        for src in SRC:
            # Some day, the preprocess builder should be fixed so it can do multiple commands
            # in parallel but until then, just submit them one at a time
            pp_files.extend(pp_env.Preprocess(src))
        parsed_files = parse_pp(pp_env, pp_files)
        header = consolidate_pp(pp_env, parsed_files)

        Depends(cart_targets, header)

    cart_lib = denv.d_library('cart', [cart_targets, swim_targets], SHLIBVERSION=CART_VERSION)
    denv.InstallVersionedLib('$PREFIX/lib64/', cart_lib, SHLIBVERSION=CART_VERSION)

    Default(cart_lib)
    Export('cart_targets')


if __name__ == "SCons.Script":
    scons()
